package com.example.ossdemo.controller;

import com.aliyun.oss.*;
import com.aliyun.oss.internal.OSSHeaders;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.aliyun.oss.model.StorageClass;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.URL;
import java.util.*;

/**
 * @author hang
 * @version 1.0
 * Create by 2022/8/26 9:34
 * @ClassName Demo
 * @Description TODO
 */
//@RestController
//@RequestMapping("/url")
public class Demo {

        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = "oss-cn-hangzhou.aliyuncs.com";
        // 从STS服务获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        String accessKeyId = "LTAI5tLE1vqPwywXY72qFL5q";
        String accessKeySecret = "dKiPD6O1jHNK33yKnPUlhfA7hSkWnq";
        // 从STS服务获取的安全令牌（SecurityToken）。
//        String securityToken = "yourSecurityToken";
        // 填写Bucket名称，例如examplebucket。
        String bucketName = "soec1";
        // 填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = "soec/今日任务.md";
        // 填写下载到本地文件的完整路径。
        String pathName = "D:\\8.md";
//        @RequestMapping("/a")
        public void url() throws IOException {
            // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient(既这里的accessKeyId和accessKeySecret为STS服务返回的)。
            // 使用STS创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
            // 不使用STS创建OSSClient实例。
            // OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

            // 设置请求头。
            Map<String, String> headers = new HashMap<String, String>();
        /*// 指定Object的存储类型。
        headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
        // 指定ContentType。
        headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/

            // 设置用户自定义元信息。
            Map<String, String> userMetadata = new HashMap<String, String>();
        /*userMetadata.put("key1","value1");
        userMetadata.put("key2","value2");*/

            URL signedUrl = null;
        try {
            // 指定生成的签名URL过期时间，单位为毫秒。
            Date expiration = new Date(System.currentTimeMillis() + 30L * 1000);
            System.out.println("expiration = " + expiration);
            long time = expiration.getTime();
            System.out.println("time = " + time);

            // 生成签名URL。
            GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
            // 设置过期时间。
            request.setExpiration(expiration);
            // 将请求头加入到request中。
            request.setHeaders(headers);
            // 添加用户自定义元信息。
            request.setUserMetadata(userMetadata);

            // 设置查询参数。
            // Map<String, String> queryParam = new HashMap<String, String>();
            // 指定IP地址或者IP地址段。
            // queryParam.put("x-oss-ac-source-ip","110.191.179.0");
            // 指定子网掩码中1的个数。
            // queryParam.put("x-oss-ac-subnet-mask","32");
            // 指定VPC ID。
            // queryParam.put("x-oss-ac-vpc-id","vpc-12345678");
            // 指定是否允许转发请求。
            // queryParam.put("x-oss-ac-forward-allow","true");
            // request.setQueryParameter(queryParam);

            // 设置单链接限速，单位为bit，例如限速100 KB/s。
//             request.setTrafficLimit(100 * 1024 * 8);

            // 通过HTTP GET请求生成签名URL。
            signedUrl = ossClient.generatePresignedUrl(request);
//            // 打印签名URL。
            System.out.println("signed url for putObject: " + signedUrl);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        }

            // 通过签名URL下载文件，以HttpClients为例说明。
        getObjectWithHttp(signedUrl, pathName, headers, userMetadata);
    }

    public static void getObjectWithHttp(URL signedUrl, String pathName, Map<String, String> headers, Map<String, String> userMetadata) throws IOException {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            HttpGet get = new HttpGet(signedUrl.toURI());
            // 如果生成签名URL时设置了header参数，例如用户元数据，存储类型等，则调用签名URL下载文件时，也需要将这些参数发送至服务端。如果签名和发送至服务端的不一致，会报签名错误。
            for(Map.Entry header: headers.entrySet()){
                get.addHeader(header.getKey().toString(),header.getValue().toString());
            }
            for(Map.Entry meta: userMetadata.entrySet()){
                get.addHeader(meta.getKey().toString(),meta.getValue().toString());
            }

            httpClient = HttpClients.createDefault();
            response = httpClient.execute(get);

            System.out.println("返回下载状态码："+response.getStatusLine().getStatusCode());
            if(response.getStatusLine().getStatusCode() == 200){
                System.out.println("使用网络库下载成功");
            }
            System.out.println(response.toString());

            // 保存文件到磁盘。
            saveFileToLocally(response.getEntity().getContent(), pathName);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            response.close();
            httpClient.close();
        }
    }

    public static void saveFileToLocally(InputStream inputStream, String pathName) throws IOException {
        DataInputStream in = null;
        OutputStream out = null;
        try {
            in = new DataInputStream(inputStream);
            out = new DataOutputStream(new FileOutputStream(pathName));
            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = in.read(bufferOut)) != -1) {
                out.write(bufferOut, 0, bytes);
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            in.close();
            out.close();
        }
    }

}

